home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / Apple Game Sprockets / RAVE SDK 1.06 GM for MacOS / Example Projects / GameScene / GSPicture.c < prev    next >
Encoding:
Text File  |  1996-03-21  |  14.7 KB  |  571 lines  |  [TEXT/MPS ]

  1. // ===========================================================================
  2. //    
  3. //     GSPicture.c 
  4. //    
  5. //    Copyright (C) 1996 Apple Computer, Inc.  All rights reserved.
  6. //
  7. // ===========================================================================
  8.  
  9.  
  10. // ===========================================================================
  11. //    Includes
  12. // ===========================================================================
  13.  
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16.  
  17. #if (kQAPlatform == kQAMacOS)
  18.     #include <Memory.h>
  19.     #include <QuickDraw.h>
  20.     #include <PictUtil.h>
  21. #endif
  22.  
  23. #include "RAVE.h"
  24.  
  25. #include "GSPicture.h"
  26. #include "GSColorTable.h"
  27. #include "GSUtilities.h"
  28. #include "GSError.h"
  29.  
  30.  
  31. // ===========================================================================
  32. //    Constants
  33. // ===========================================================================
  34.  
  35. #if (kQAPlatform == kQAMacOS)
  36.     #define                 kPICTFileHeaderLength            512
  37. #endif
  38.  
  39.  
  40. // ===========================================================================
  41. //    Types
  42. // ===========================================================================
  43.  
  44. typedef struct TGSPicture {
  45.     TQAImagePixelType         mPixelType;
  46.     long                    mWidth;
  47.     long                    mHeight;
  48.     long                    mRowBytes;
  49.     void*                    mPixMap;
  50.     TGSColorTable*            mColorTable;
  51. #if (kQAPlatform == kQAMacOS)
  52.     GWorldPtr                mGWorld;
  53.     PicHandle                mPICTHandle;
  54. #endif
  55. } TGSPicture;
  56.  
  57.  
  58. // ===========================================================================
  59. //    Private Prototypes
  60. // ===========================================================================
  61.  
  62.     TGSError
  63. GSPicture_CreateFileStorage(
  64.     TGSPicture*                inPicture,
  65.     FILE*                    inPictureFile);
  66.     TGSError
  67. GSPicture_DeleteFileStorage(
  68.     TGSPicture*                inPicture,
  69.     FILE*                    inPictureFile);
  70.     TGSError
  71. GSPicture_ReadFromFile(
  72.     TGSPicture*                inPicture,
  73.     FILE*                    inPictureFile);
  74.     TGSError
  75. GSPicture_CreatePixMap(
  76.     TGSPicture*                inPicture);
  77.  
  78.  
  79. // ===========================================================================
  80. //    Public Routines
  81. // ===========================================================================
  82.  
  83. // ===========================================================================
  84. //    GSPicture_New
  85. // ===========================================================================
  86.     TGSError
  87. GSPicture_New(
  88.     TGSPicture**            inPicture)
  89. {
  90.     *inPicture = (TGSPicture*) malloc(sizeof(TGSPicture));
  91.     
  92.     if (*inPicture == nil) {
  93.         return kGSError_NotEnoughMemory;
  94.     }
  95.     
  96.     (**inPicture).mPixelType = kQAPixel_RGB32;
  97.     (**inPicture).mWidth = 0;
  98.     (**inPicture).mHeight = 0;
  99.     (**inPicture).mRowBytes = 0;
  100.     (**inPicture).mPixMap = nil;
  101.     (**inPicture).mColorTable = nil;
  102. #if (kQAPlatform == kQAMacOS)
  103.     (**inPicture).mGWorld = nil;
  104.     (**inPicture).mPICTHandle = nil;
  105. #endif
  106.     
  107.     return kGSError_None;
  108. }
  109.  
  110.  
  111. // ===========================================================================
  112. //    GSPicture_NewFromPath
  113. // ===========================================================================
  114.     TGSError
  115. GSPicture_NewFromPath(
  116.     TGSPicture**            inPicture,
  117.     TQAImagePixelType         inPixelType,
  118.     const char*                inPath)
  119. {
  120.     FILE*                    pictureFile;
  121.     TGSError                gsError;
  122.     
  123.         // open the file for reading
  124.     pictureFile = fopen(inPath, "rb");
  125.     
  126.     if (pictureFile == nil) {
  127.         return kGSError_FileNotFound;
  128.     }
  129.     
  130.         // now that we have a file pointer, we can call this constructor to
  131.         // actually create the GSPicture
  132.     gsError = GSPicture_NewFromFile(inPicture, inPixelType, pictureFile);
  133.  
  134.         // GSPicture_NewFromFile doesn't close the file itself, so we have to 
  135.     fclose(pictureFile);
  136.     
  137.     return gsError;
  138. }
  139.  
  140.  
  141. // ===========================================================================
  142. //    GSPicture_NewFromFile
  143. // ===========================================================================
  144.     TGSError
  145. GSPicture_NewFromFile(
  146.     TGSPicture**            inPicture,
  147.     TQAImagePixelType         inPixelType,
  148.     FILE*                    inPictureFile)
  149. {
  150.     TGSError                gsError;
  151.     
  152.     GSAssert_(inPictureFile);
  153.  
  154.         // initialize the GSPicture structure
  155.     gsError = GSPicture_New(inPicture);
  156.  
  157.     if (gsError != kGSError_None) {
  158.         GSPicture_Delete(*inPicture);
  159.         return gsError;
  160.     }
  161.     
  162.     (**inPicture).mPixelType = inPixelType;
  163.     
  164.     gsError = GSPicture_CreateFileStorage(*inPicture, inPictureFile);
  165.     
  166.     if (gsError != kGSError_None) {
  167.         GSPicture_Delete(*inPicture);
  168.         return gsError;
  169.     }
  170.     
  171.     gsError = GSPicture_ReadFromFile(*inPicture, inPictureFile);
  172.     
  173.     if (gsError != kGSError_None) {
  174.         GSPicture_Delete(*inPicture);
  175.         return gsError;
  176.     }
  177.     
  178.     gsError = GSPicture_CreatePixMap(*inPicture);
  179.     
  180.     if (gsError != kGSError_None) {
  181.         GSPicture_Delete(*inPicture);
  182.         return gsError;
  183.     }
  184.     
  185.     return kGSError_None;
  186. }
  187.  
  188.  
  189. // ===========================================================================
  190. //    GSPicture_Delete
  191. // ===========================================================================
  192.     void
  193. GSPicture_Delete(
  194.     TGSPicture*                inPicture)
  195. {
  196.     if (inPicture == nil) {
  197.         return;
  198.     }
  199.  
  200.     if (inPicture->mColorTable != nil) {
  201.         GSColorTable_Delete(inPicture->mColorTable);
  202.         inPicture->mColorTable = nil;
  203.     }
  204.     
  205. #if (kQAPlatform == kQAMacOS)
  206.         // the PICT handle should have been disposed of in DeleteFileStorage,
  207.         // but an error may have occurred before that could happen, which would
  208.         // cause GSPicture_Delete to be called, so we check if we need to 
  209.         // dispose of it here, just in case
  210.     if (inPicture->mPICTHandle != nil) {
  211.         KillPicture(inPicture->mPICTHandle);
  212.         inPicture->mPICTHandle = nil;
  213.     }
  214.     
  215.     if (inPicture->mGWorld != nil) {
  216.         DisposeGWorld(inPicture->mGWorld);
  217.         inPicture->mGWorld = nil;
  218.     }
  219. #endif
  220.  
  221.         // we've disposed of all the memory pointed to by the TGSPicture, so
  222.         // now we can dispose of that struct itself
  223.     free(inPicture);
  224. }
  225.  
  226.  
  227. // ===========================================================================
  228. //    GSPicture_GetWidth
  229. // ===========================================================================
  230.     long
  231. GSPicture_GetWidth(
  232.     TGSPicture*                inPicture)
  233. {
  234.     GSAssert_(inPicture);
  235.     
  236.     return inPicture->mWidth;
  237. }
  238.  
  239. // ===========================================================================
  240. //    GSPicture_GetHeight
  241. // ===========================================================================
  242.     long
  243. GSPicture_GetHeight(
  244.     TGSPicture*                inPicture)
  245. {
  246.     GSAssert_(inPicture);
  247.     
  248.     return inPicture->mHeight;
  249. }
  250.  
  251.  
  252. // ===========================================================================
  253. //    GSPicture_GetRowBytes
  254. // ===========================================================================
  255.     long
  256. GSPicture_GetRowBytes(
  257.     TGSPicture*                inPicture)
  258. {
  259.     GSAssert_(inPicture);
  260.     
  261.     return inPicture->mRowBytes;
  262. }
  263.  
  264.  
  265. // ===========================================================================
  266. //    GSPicture_GetPixMap
  267. // ===========================================================================
  268.     void*
  269. GSPicture_GetPixMap(
  270.     TGSPicture*                inPicture)
  271. {
  272.     GSAssert_(inPicture);
  273.     
  274.     return inPicture->mPixMap;
  275. }
  276.  
  277.  
  278. // ===========================================================================
  279. //    GSPicture_GetPixelType
  280. // ===========================================================================
  281.     TQAImagePixelType
  282. GSPicture_GetPixelType(
  283.     TGSPicture*                inPicture)
  284. {
  285.     GSAssert_(inPicture);
  286.     
  287.     return inPicture->mPixelType;
  288. }
  289.  
  290.  
  291. // ===========================================================================
  292. //    GSPicture_GetColorTable
  293. // ===========================================================================
  294.     TGSColorTable*
  295. GSPicture_GetColorTable(
  296.     TGSPicture*                inPicture)
  297. {
  298.     GSAssert_(inPicture);
  299.     
  300.     return inPicture->mColorTable;
  301. }
  302.  
  303.  
  304. // ===========================================================================
  305. //    Private Routines
  306. // ===========================================================================
  307.  
  308. // ===========================================================================
  309. //    GSPicture_CreateFileStorage
  310. // ===========================================================================
  311.     TGSError
  312. GSPicture_CreateFileStorage(
  313.     TGSPicture*                inPicture,
  314.     FILE*                    inPictureFile)
  315. {
  316.     long                    fileLength = 0;
  317.     
  318.     GSAssert_(inPicture);
  319.     GSAssert_(inPictureFile);
  320.     
  321.         // position the file pointer at the end of the file
  322.     if (fseek(inPictureFile, 0, SEEK_END)) {
  323.             // fseek returns non-zero on error
  324.         return kGSError_FileSystem;
  325.     };
  326.     
  327.         // get the current position of the file pointer, which should be
  328.         // equivalent to the length of the file
  329.     fileLength = ftell(inPictureFile);
  330.     
  331.     if (fileLength == -1L) {
  332.             // ftell returns -1L on error
  333.         return kGSError_FileSystem;
  334.     }
  335.     
  336. #if (kQAPlatform == kQAMacOS)
  337.         // there is a 512-byte comment header on PICT files which we ignore
  338.     fileLength -= kPICTFileHeaderLength;
  339.  
  340.         // allocate the memory to store the picture from the file
  341.     inPicture->mPICTHandle = (PicHandle) NewHandle(fileLength);
  342.     
  343.     if (inPicture->mPICTHandle == nil) {
  344.         return kGSError_NotEnoughMemory;
  345.     }
  346. #endif    
  347.  
  348.     return kGSError_None;
  349. }
  350.  
  351.  
  352. // ===========================================================================
  353. //    GSPicture_DeleteFileStorage
  354. // ===========================================================================
  355.     TGSError
  356. GSPicture_DeleteFileStorage(
  357.     TGSPicture*                inPicture,
  358.     FILE*                    inPictureFile)
  359. {
  360.     GSAssert_(inPicture);
  361.     GSAssert_(inPictureFile);
  362.     
  363. #if (kQAPlatform == kQAMacOS)
  364.     GSAssert_(inPicture->mPICTHandle);
  365.     
  366.     KillPicture(inPicture->mPICTHandle);
  367.     inPicture->mPICTHandle = nil;
  368. #endif    
  369.  
  370.     return kGSError_None;
  371. }    
  372.  
  373.  
  374. // ===========================================================================
  375. //    GSPicture_ReadFromFile
  376. // ===========================================================================
  377.     TGSError
  378. GSPicture_ReadFromFile(
  379.     TGSPicture*                inPicture,
  380.     FILE*                    inPictureFile)
  381. {
  382.     long                    bytesRead = 0;
  383.     
  384.     GSAssert_(inPicture);
  385.     GSAssert_(inPictureFile);
  386.     
  387. #if (kQAPlatform == kQAMacOS)
  388.     GSAssert_(inPicture->mPICTHandle);
  389.     
  390.         // position the file pointer past the 512-byte PICT header
  391.     if (fseek(inPictureFile, kPICTFileHeaderLength, SEEK_SET)) {
  392.             // fseek returns non-zero on error
  393.         return kGSError_FileSystem;
  394.     };
  395.     
  396.     HLockHi((Handle) inPicture->mPICTHandle);
  397.     
  398.         // read 1 object the size of the PicHandle into the PicHandle
  399.     bytesRead = fread(*inPicture->mPICTHandle, 1,
  400.             GetHandleSize((Handle) inPicture->mPICTHandle), inPictureFile);
  401.     
  402.     HUnlock((Handle) inPicture->mPICTHandle);
  403.     
  404.     if (bytesRead != GetHandleSize((Handle) inPicture->mPICTHandle)) {
  405.         return kGSError_FileSystem;
  406.     }
  407. #endif    
  408.  
  409.     return kGSError_None;
  410. }    
  411.  
  412.  
  413. // ===========================================================================
  414. //    GSPicture_CreatePixMap
  415. // ===========================================================================
  416.     TGSError
  417. GSPicture_CreatePixMap(
  418.     TGSPicture*                inPicture)
  419. {
  420. #if (kQAPlatform == kQAMacOS)
  421.     TQAColorTableType        colorTableType = kQAColorTable_CL8_RGB32;
  422.     PictInfo                 info;
  423.     short                     depth = 0;
  424.     short                     pictInfoVerb = 0;
  425.     short                     colorsRequested = 0;
  426.  
  427.     GSAssert_(inPicture);
  428.  
  429.         // figure out how deep the GWorld will have to be, and whether we want
  430.         // to extract the PICT's color table
  431.     switch (inPicture->mPixelType) {
  432.         case kQAPixel_RGB32:
  433.         case kQAPixel_ARGB32:
  434.             depth = 32;
  435.             break;
  436.         
  437.         case kQAPixel_RGB16:
  438.         case kQAPixel_ARGB16:
  439.             depth = 16;
  440.             break;
  441.         
  442.         case kQAPixel_CL8:
  443.             colorTableType = kQAColorTable_CL8_RGB32;
  444.             depth = 8;
  445.             pictInfoVerb = returnColorTable;
  446.             colorsRequested = 256;
  447.             break;
  448.             
  449.         case kQAPixel_CL4:
  450.             colorTableType = kQAColorTable_CL4_RGB32;
  451.             depth = 4;
  452.             pictInfoVerb = returnColorTable;
  453.             colorsRequested = 16;
  454.             break;
  455.             
  456.         case kQAPixel_Alpha1:
  457.             depth = 1;
  458.             break;
  459.             
  460.         default:
  461.             GSAssert_(!"Found unrecognized TQAImagePixelType in GSPicture_CreatePixMap.");
  462.             break;
  463.     } 
  464.  
  465.         // calc the PICT's height and width.  we use GetPictInfo to get the 
  466.         // sourceRect of the PICT because that contains the full size of the 
  467.         // image and ignores the Hres and Vres values.  so we can use the PICT 
  468.         // even if it's not 72 dpi.  we also get the pict's color table if this 
  469.         // is a color table texture, using either 16 or 256 colors and the 
  470.         // median method for picking the colors.
  471.     GetPictInfo(inPicture->mPICTHandle, &info, pictInfoVerb, colorsRequested, 
  472.             medianMethod, 0);    
  473.  
  474.     inPicture->mWidth = info.sourceRect.right - info.sourceRect.left;
  475.     inPicture->mHeight = info.sourceRect.bottom - info.sourceRect.top;
  476.  
  477.         // load the PICT into a new GWorld of the appropriate depth
  478.     {
  479.         CGrafPtr            savedPort;
  480.         GDHandle            savedDevice;
  481.         Rect                pictRect = { 0, 0, 0, 0 };
  482.         QDErr                error;
  483.         
  484.         GetGWorld(&savedPort, &savedDevice);
  485.         
  486.         pictRect.right = inPicture->mWidth;
  487.         pictRect.bottom = inPicture->mHeight;
  488.         
  489.             // create an offscreen GWorld of the appropriate size and depth
  490.         error = NewGWorld(&inPicture->mGWorld, depth, &pictRect, 
  491.                 info.theColorTable, nil, 0);
  492.         
  493.         if (inPicture->mGWorld == nil) {
  494.                 // there wasn't enough space to create the GWorld in the app
  495.                 // heap, so try system memory
  496.             error = NewGWorld(&inPicture->mGWorld, depth, &pictRect, 
  497.                     info.theColorTable, nil, useTempMem);
  498.         }
  499.         
  500.         if (inPicture->mGWorld == nil || error != noErr) {
  501.                 // we still don't have enough memory to create the GWorld or
  502.                 // some other error occurred.  before returning, we have to
  503.                 // dispose of the color table handle which was possibly 
  504.                 // allocated for the PICT info.
  505.             if (info.theColorTable != nil) {
  506.                 DisposeHandle((Handle) info.theColorTable);
  507.             }
  508.             
  509.             return kGSError_NotEnoughMemory;
  510.         }
  511.         
  512.             // prepare to work with the GWorld
  513.         SetGWorld(inPicture->mGWorld, nil);
  514.         
  515.         SetOrigin(0, 0);
  516.         
  517.             // prepare to draw into the GWorld.  we'll leave the pixels locked
  518.             // even after we're finished drawing because we use the GWorld as
  519.             // a pixmap to create a texture, so we don't want it to move. 
  520.         if (LockPixels(GetGWorldPixMap(inPicture->mGWorld)) != true) {
  521.             return kGSError_OS;
  522.         }
  523.         
  524.         EraseRect(&pictRect);
  525.         
  526.             // draw the PICT into the GWorld
  527.         DrawPicture(inPicture->mPICTHandle, &pictRect);
  528.         
  529.         if (depth == 1) {
  530.                 // in a 1-bit GWorld, 1 == black and 0 == white, which is the 
  531.                 // opposite of what we want, so invert the bitmap
  532.             InvertRect(&pictRect);
  533.         }
  534.  
  535.             // revert to the previous GWorld
  536.         SetGWorld(savedPort, savedDevice);
  537.  
  538.             // we've drawn the picture, so we can get rid of the handle now
  539.         KillPicture(inPicture->mPICTHandle);
  540.         inPicture->mPICTHandle = nil;
  541.     }    
  542.     
  543.         // to get the pixmap's actual rowbytes, we have to mask off the top two bits
  544.     inPicture->mRowBytes = (**(GetGWorldPixMap(inPicture->mGWorld))).rowBytes & 0x3fff;
  545.  
  546.         // save the GWorld's base address
  547.     inPicture->mPixMap = GetPixBaseAddr(GetGWorldPixMap(inPicture->mGWorld));
  548.     
  549.     if (pictInfoVerb == returnColorTable) {
  550.             // this is a CL4 or CL8 texture, so we have to create a TGSColorTable
  551.             // out of the CTabHandle we extracted from the PICT
  552.         TGSError            gsError;
  553.         
  554.         GSAssert_(info.theColorTable);
  555.         
  556.         gsError = GSColorTable_NewFromMacColorTable(&inPicture->mColorTable, 
  557.                 colorTableType, info.theColorTable);
  558.     
  559.             // GetPictInfo creates a color table handle which we're responsible
  560.             // for disposing of
  561.         DisposeHandle((Handle) info.theColorTable);
  562.             
  563.         if (gsError != kGSError_None) {
  564.             return gsError;
  565.         }
  566.     }
  567. #endif    
  568.  
  569.     return kGSError_None;
  570. }
  571.